package com.snailhd.cloud.account.service.impl;

import com.alibaba.fastjson.JSON;
import com.snailhd.cloud.account.entity.UserDO;
import com.snailhd.cloud.account.spi.TokenService;
import com.snailhd.cloud.account.entity.LoginDTO;
import com.snailhd.cloud.account.entity.LoginResultVO;
import com.snailhd.cloud.account.entity.TokenDTO;
import com.snailhd.cloud.account.spi.UserService;
import com.snailhd.common.constant.RedisConstant;
import com.snailhd.common.entity.IResult;
import com.snailhd.common.enums.RespSubCodeEnum;
import com.snailhd.cloud.redis.service.RedisService;
import com.snailhd.common.util.base.AESUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;


@Slf4j
@Service
public class TokenServiceImpl implements TokenService {

    /**登录有效期*/
    private int effectiveMin = 60 * 24 * 15;

    @Reference(check = false)
    private UserService userService;

    @Resource
    RedisService redisService;

    @Override
    public IResult<LoginResultVO> login(LoginDTO loginDTO) {
        IResult<LoginResultVO> re = new IResult<LoginResultVO>();

        UserDO userDO = null;
        if(loginDTO.getAccount().contains("@")){
            userDO = userService.queryByEmail(loginDTO.getAccount());
        }else{
            userDO = userService.queryByPhone(Long.parseLong(loginDTO.getAccount()));
        }

        //账号不存在
        if(userDO ==null) {
            return re.setSubMsg(RespSubCodeEnum.ACCOUNT_NOT_EXIST.generalSubMsg());
        }

        TokenDTO tokenDTO = TokenDTO.getInstance(userDO.getAid());
        String token = null;
        String tokenJsonStr = JSON.toJSONString(tokenDTO);
        try {
            token =  AESUtil.encry(tokenJsonStr);

            effectiveMin = redisService.hgetConfigStrToInteger(RedisConstant.SYS_CONFIG,RedisConstant.TOKEN_EFFECTIVE_TIME, effectiveMin);
            redisService.setex(RedisConstant.TOKEN+ userDO.getAid(),effectiveMin*60, token);
            saveToRedis(userDO);

            LoginResultVO loginResult = new LoginResultVO(token);
            re.setData(loginResult);
        } catch (Exception e) {
            log.error("token 生成失败："+tokenJsonStr, e.getMessage());
            throw new RuntimeException("token 生成失败",e);
        }

        return re;
    }

    @Override
    public IResult logout(String userId) {
        redisService.del(RedisConstant.TOKEN+userId);
        return new IResult();
    }

    @Override
    public IResult<UserDO> verifyToken(String token) throws Exception {

        TokenDTO tokenDTO = null;
        String text = AESUtil.decry(token);
        tokenDTO = JSON.parseObject(text, TokenDTO.class);

        String tokenForDb = redisService.get(RedisConstant.TOKEN+tokenDTO.getId());
        if(StringUtils.isEmpty(tokenForDb) || !token.equals(tokenForDb)){
            return new IResult<UserDO>().setSubMsg(RespSubCodeEnum.PALCE_LOGIN.generalSubMsg());
        }
        UserDO userDO = getByIdFromCacheOrDb(tokenDTO.getId());
        return new IResult<UserDO>(userDO);
    }

    private String saveToRedis(UserDO userDO) {
        return redisService.setex(RedisConstant.ACCOUNT_INFO+userDO.getAid(),effectiveMin*60, JSON.toJSONString(userDO));
    }

    private UserDO getByIdFromCacheOrDb(long id){
        UserDO user = null;
        String accountStr = redisService.get(RedisConstant.ACCOUNT_INFO+id);
        if(StringUtils.isEmpty(accountStr)) {
            user = userService.queryById(id);
            saveToRedis(user);
        }else {
            user = JSON.parseObject(accountStr, UserDO.class);
        }
        return user;
    }
}
